package main

import (
	"bs10-interface/mock"
	"bs10-interface/real"
	"fmt"

	"time"
)

/*
接口实现是隐式的
只要实现接口里面的方法

接口变量
实现者的类型
实现者的指针(值)

查看接口变量
表示任何类型: interface{}
Type Assertion
Type Switch
*/

// Retriever 定义 Retriever 是一个接口
// 接收数据
type Retriever interface {
	//不需要添加 func 关键字, 因为接口中全是函数
	Get(url string) string
}

type Poster interface {
	Post(url string,
		form map[string]string) string
}

const url = "http://www.baidu.com"

func download(r Retriever) string {
	return r.Get(url)
}

func post(poster Poster) {
	poster.Post(url,
		map[string]string{
			"name":   "ccmouse",
			"course": "golang",
		})
}

//接口的组合(根据需要)
type RetrieverPoster interface {
	Retriever //接收
	Poster    //发送
}

func session(s RetrieverPoster) string {
	s.Post(url, map[string]string{
		"contents": "another faked baidu.com",
	})
	return s.Get(url)
}

func main() {
	var r Retriever

	//mock 调用
	mockRetriever := mock.Retriever{
		Contents: "this is a fake https://www.baidu.com",
	}
	r = &mockRetriever
	inspect(r)

	//真实 http 请求
	r = &real.Retriever{
		UserAgent: "Mozilla/5.0",
		TimeOut:   time.Minute,
	}
	inspect(r)

	// Type assertion, 判断变量是否为指定的类型 r.(*mock.Retriever)
	// 返回值为: 实现者的指针 和 是否是判断的类型
	if retrieverPointer, ok := r.(*mock.Retriever); ok {
		fmt.Println(retrieverPointer.Contents)
	} else {
		fmt.Println("r is not a mock retriever")
	}

	fmt.Println()
	fmt.Println("Try a session with mockRetriever")
	//mockRetriever既实现了 Retriever 接口, 也实现了 RetrieverPoster 这个组合接口
	fmt.Println(session(&mockRetriever))
	fmt.Println()
}

func inspect(r Retriever) {
	fmt.Println("对象打印,", r)
	//%T 查看对象类型, %v 查看对象值
	fmt.Printf(" > Type:%T Value:%v\n", r, r)
	fmt.Print(" > Type switch: ")
	//根据类型进行处理
	switch v := r.(type) {
	case *mock.Retriever:
		fmt.Println("Contents:", v.Contents)
	case *real.Retriever:
		fmt.Println("UserAgent:", v.UserAgent)
	}
	fmt.Println()
}
